<?php

declare(strict_types=1);

namespace App\Common\Service;

use App\Setting\Service\SettingConfigService;
use GuzzleHttp\Client;
use Hyperf\Codec\Packer\JsonPacker;
use Hyperf\Contract\PackerInterface;
use Hyperf\Coroutine\Coroutine;
use Hyperf\Guzzle\CoroutineHandler;
use Mine\Abstracts\AbstractService;
use Mine\Exception\NormalStatusException;

/**
 * 微客云服务
 */
class WkyService extends AbstractService
{
    protected Client $client;

    protected PackerInterface $packer;

    protected $secret = 'ZTZkNjUxYzQ0NDVkOGU1N2UzM2QyMTBkNTNjYjA5NmIxMmFhYTY0MTAzNTM1ZDlkOGI2MjBjNDQ5ZjViZjI3OQ==';

    public function __construct(PackerInterface $packer = null)
    {
        $handler = null;
        if (Coroutine::inCoroutine()) {
            $handler = new CoroutineHandler();
        }
        $baseUri = container()->get(SettingConfigService::class)->getConfigByKey('saas_api_host')['value'] ?? '';
        $this->client = new Client([
            'base_uri' => $baseUri,
            'timeout' => 3,
            'handler' => $handler,
        ]);
        $this->packer = $packer ?? new JsonPacker();
    }

    /**
     * 获取登录二维码
     * @param mixed $officialId
     * @return mixed
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    public function getLoginQrCode(mixed $officialId): mixed
    {
        $params = [
            'official_id' => $officialId
        ];

        $signData = $this->generateSignature($params,$this->secret);
        $params = array_merge($params,$signData);
        $response = $this->client->post('/api/cust_hub/getLoginQrcode', [
            'json' => $params
        ]);
        $data = $this->packer->unpack((string) $response->getBody());
        if(!empty($data) && $data['code'] == 1){
            return $data['data'];
        }else{
            throw new NormalStatusException('登录二维码获取失败,请刷新重新获取');
        }
    }

    /**
     * 生成签名
     *
     * @param array  $params   请求参数
     * @param string $secret   签名密钥
     * @param int    $expires  签名有效期（秒）
     * @return array           签名及相关数据
     */
    public function generateSignature(array $params, string $secret, int $expires = 300): array {
        // 添加时间戳和随机数
        $params['timestamp'] = time();
        $params['expires'] = $expires;

        // 按照键名升序排序参数
        ksort($params);

        // 构造待签名的字符串
        $signString = '';
        foreach ($params as $key => $value) {
            if (is_array($value) || is_object($value)) {
                // 对于数组或对象类型，只拼接键名
                $signString .= $key . '&';
            } elseif (is_null($value) || is_bool($value)) {
                // 对于空值或布尔值，转换为空字符串
                $signString .= $key . '=&';
            } else {
                // 对于其他类型，直接使用字符串形式的值
                $signString .= $key . '=' . $value . '&';
            }
        }
        $signString = rtrim($signString, '&');

        // 使用HMAC-SHA256算法生成签名
        $signature = hash_hmac('sha256', $signString, $secret);

        return [
            'signature' => $signature,
            'timestamp' => $params['timestamp'],
            'expires' => $expires
        ];
    }
}